// Contient toutes les spécifications de classes nécessaires
// pour représenter l'arbre abstrait
#ifndef ARBRE_H_
#define ARBRE_H_

#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;

#include "Symbole.h"
#include "Valeur.h"

////////////////////////////////////////////////////////////////////////////////
class Noeud {
// classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
// Remarque : la classe ne contient aucun constructeur
  public:
    virtual Valeur*  getValeur() {
        Valeur* valeur = new ValeurInt(0);
        return valeur;
    }; // méthode pure (non implémentée) qui rend la classe abstraite
    virtual void afficher(unsigned short indentation=0) { cout << setw(4*indentation) << " "; }
      // pour afficher un noeud avec un décalage (indentation) proportionnel à son niveau dans l'arbre

    virtual ~Noeud() {} // présence d'un destructeur virtuel conseillée dans les classes abstraites
};

////////////////////////////////////////////////////////////////////////////////
class NoeudSeqInst : public Noeud {
// classe pour représenter un noeud "sequence d'instruction"
// qui a autant de fils que d'instructions dans la séquence
  public:
     NoeudSeqInst();   // construit une séquence d'instruction vide
    ~NoeudSeqInst() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue chaque instruction de la séquence
    void afficher(unsigned short indentation=0); // affiche la séquence d'instructions
    void ajouteInstruction(Noeud* instruction);  // ajoute une instruction à la séquence

  private:
    vector<Noeud *> tabInst; // pour stocker les instructions de la séquence
};

////////////////////////////////////////////////////////////////////////////////
class NoeudAffectation : public Noeud {
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
  public:
     NoeudAffectation(Noeud* variable, Noeud* expression); // construit une affectation
    ~NoeudAffectation() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short indentation=0); // affiche l'affectation

  private:
    Noeud* variable;
    Noeud* expression;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurBinaire : public Noeud {
// classe pour représenter un noeud "opération arithmétique" composé d'un opérateur (+-*/)
// et de 2 fils : l'opérande gauche et l'opérande droit
  public:
    NoeudOperateurBinaire(Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit);
     // construit une opération binaire : operandeGauche operateur OperandeDroit
   ~NoeudOperateurBinaire() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur(); // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short indentation=0); // affiche l'opération

  private:
    Symbole operateur;
    Noeud*  operandeGauche;
    Noeud*  operandeDroit;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurUnaire : public Noeud {
public:
    NoeudOperateurUnaire(Symbole operateur, Noeud* operande);
    ~NoeudOperateurUnaire(){}
    Valeur* getValeur();
    void afficher(unsigned short indentation=0);
private:
    Symbole operateur;
    Noeud* operande;
};

class NoeudInstSi : public Noeud {
// classe pour représenter un noeud "si"
// composé de 3 fils : la seqInst et la condition d'entree, et le si suivant s'il existe.
public:
    NoeudInstSi ( Noeud* expbool, Noeud* seqInst, Noeud* siSuivant ); // construit un si
    ~NoeudInstSi() {} // à cause du destructeur virtuel de la classe Noeud
    Valeur* getValeur();
    void afficher(unsigned short indentation);
    inline void setSiSuivant(Noeud* s) { this->siSuivant = s; }
    inline void setExpBool(Noeud* e) {this->expBool = e;}

private:
    Noeud* seqInst;
    Noeud* expBool;
    Noeud* siSuivant;
};

class NoeudInstPour : public Noeud {    
public :
    NoeudInstPour(Noeud* iterateur, Noeud* condition, Noeud* incrementation, Noeud* seqInst);
    ~NoeudInstPour() {}
    Valeur* getValeur();
    void afficher(unsigned short indentation);
private :
    Noeud* affectation;
    Noeud* expBool;
    Noeud* affectationDroite;
    Noeud* seqInst;
};

class NoeudInstTantQue : public Noeud {
public:
    NoeudInstTantQue(Noeud* expbool, Noeud* seqinst);
    ~NoeudInstTantQue(){}
    Valeur* getValeur();
    void afficher(unsigned short indentation=0);
private:
    Noeud* seqInst;
    Noeud* expBool;
};

class NoeudInstRepeter : public Noeud {
public:
     NoeudInstRepeter(Noeud* expbool, Noeud* seqinst);
    ~NoeudInstRepeter(){}
    Valeur* getValeur();
    void afficher(unsigned short indentation=0);
private:
    Noeud* seqInst;
    Noeud* expBool;
};


class NoeudInstSwitch : public Noeud {
public :
    NoeudInstSwitch(Noeud* variable);
    ~NoeudInstSwitch(){}
    Valeur* getValeur();
    void afficher(unsigned short indentation=0);
    void ajouteCase(Noeud* conditon, Noeud* seqInst);
private :
    Noeud* variable;
    vector<Noeud*> vectConditions;
    vector<Noeud*> vectInsts;
};


class NoeudInstEcrire : public Noeud {
public:
    NoeudInstEcrire(Noeud* expression);
    ~NoeudInstEcrire() {}
    Valeur* getValeur();
    void afficher(unsigned short indentation=0);
private:
    Noeud* phrase;
};

class NoeudInstLire : public Noeud {
public:
    NoeudInstLire(Noeud* variable);
    ~NoeudInstLire() {}
    Valeur* getValeur();
    void afficher(unsigned short indentation=0);
private:
    Noeud* variable;
};

#endif /* ARBRE_H_ */
